package it.unibz.easytravel.expenses;

import java.util.Date;
import java.util.Vector;

import it.unibz.easytravel.R;
import it.unibz.easytravel.common.Person;
import it.unibz.easytravel.db.DebtsDbAdapter;
import it.unibz.easytravel.db.ExpensesDbAdapter;
import it.unibz.easytravel.db.TravellersDbAdapter;
import it.unibz.easytravel.expenses.statistic.Converter;
import it.unibz.easytravel.travel.EditTravel;

import android.app.Activity;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;

/**
 * Class is responsible for adding the expenses to the database as well as
 * performing addition of debts to the DB those comes from new expense.
 * 
 */
public class AddExpense extends Activity {

	private LinearLayout mDebtors;
	private LinearLayout mCreditor;

	public static final String _ID = "id";
	private static int travel_id;
	public int nr_of_travelers = 0;

	private ExpensesDbAdapter mExpensesDb;
	private TravellersDbAdapter mTravellersDb;
	private DebtsDbAdapter mDebtsDb;

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		SharedPreferences settings = getSharedPreferences(EditTravel.PREFS_NAME, 0);
		travel_id = settings.getInt(EditTravel.TRAVEL_ID, -1);

		setContentView(R.layout.expense_add);

		mTravellersDb = new TravellersDbAdapter(this);
		mTravellersDb.open();
		
		mExpensesDb = new ExpensesDbAdapter(this);
		mExpensesDb.open();

		mDebtsDb = new DebtsDbAdapter(this);
		mDebtsDb.open();

		mCreditor = (LinearLayout) findViewById(R.id.list_creditor);
		mDebtors = (LinearLayout) findViewById(R.id.list_debtors);

		Cursor travelersCursor = mTravellersDb.getTravellers(travel_id);

		// adds buttons of all travelers to the view
		// sets button id same as each traveler have in DB
		int id;
		while (travelersCursor.moveToNext()) {
			nr_of_travelers++;

			CheckBox newButton = new CheckBox(this);
			id = travelersCursor.getInt(travelersCursor.getColumnIndexOrThrow(TravellersDbAdapter.PERSON_ID));
			newButton.setId(id);
			newButton.setText(Person.getName(id, this));
			
			mCreditor.addView(newButton);

			newButton = new CheckBox(this);
			newButton.setId(id);

			mDebtors.addView(newButton);
		}

		Button button = (Button) findViewById(R.id.button_saveExpense);
		button.setOnClickListener(mSaveListener);
	}

	private OnClickListener mSaveListener = new OnClickListener() {

		public void onClick(View v) {
			int amnt = 0;
			int creditor = -1;
			Vector debtors = new Vector();
			String comm = "";
			boolean show = true;
			boolean calculated = false;
			Date date = new Date();

			// Gets the amount from the input field
			EditText amount = (EditText) findViewById(R.id.entry_amount);
			String tmp_str = amount.getText().toString();
			if (!tmp_str.equals(""))
				amnt = Converter.convertToIntSplit(tmp_str);
		

			// Gets the Id of traveler who is crediting
			for (int i = 0; i < nr_of_travelers; i++) {
				CheckBox t_creditor = (CheckBox) mCreditor.getChildAt(i);
				if (t_creditor.isChecked()) {
					creditor = t_creditor.getId();
					break;
				}
			}
			// if creditor is not checked issue error
			if (creditor < 0)
				;// FIXME some error handling

			// Gets the Ids of travelers who is in debt in this expense
			for (int i = 0; i < nr_of_travelers; i++) {
				CheckBox debtor = (CheckBox) mDebtors.getChildAt(i);
				if (debtor.isChecked()) {
					debtors.add(debtor.getId());
				}
			}

			// Get the comment from the input field
			EditText comment = (EditText) findViewById(R.id.entry_comment);
			comm = comment.getText().toString();

			// check for input validity
			if (amnt != 0 && creditor >= 0 && debtors.size() > 0) {
				// add debts to DB table and AmountsSpent
				// if both addition completed successfully add expense to DB
				if (addAmountsSpentForExpense(travel_id, creditor, debtors,
						amnt)
						&& addDebtsFromExpense(travel_id, creditor, debtors,
								amnt)) {
					mExpensesDb.createExpense(travel_id, amnt, creditor,
							debtors, comm, show, calculated, date);
				}
			}else{
				;//FIXME some message should be shown if some fields are missing.
			}

			// close DB connections
			mExpensesDb.close();
			mTravellersDb.close();
			mDebtsDb.close();

			setResult(RESULT_OK);
			finish();

		}
	};

	/**
	 * Method takes expense and adds it to the debts list
	 * 
	 * @param Expense
	 * @return True if expense successfully added to debts list
	 */
	public boolean addDebtsFromExpense(int travel_id, int creditor,
			Vector debtors, int amnt) {

		boolean added = false;
		int nrOfDebtorsSize = debtors.size();
		int total_debt_per_person = amnt / nrOfDebtorsSize;

		int cursor_id = -1;

		for (int i = 0; i < nrOfDebtorsSize; i++) {
			
			int debtor = ((Integer) debtors.elementAt(i)).intValue();
			// if not himself
			if (creditor != debtor) {
				boolean exist = false;
				int debt_per_person = total_debt_per_person;
				
				// if relation already exists
				cursor_id = mDebtsDb.getDebtRelationID(travel_id, creditor,
						debtor);
				if (cursor_id > 0) {
					exist = true;
					mDebtsDb.addToDebtRelation(cursor_id, debt_per_person);
				}else{

				// if reverse relation exists
				cursor_id = mDebtsDb.getDebtRelationID(travel_id, debtor,
						creditor);
				if (cursor_id > 0) {
					int delta = mDebtsDb.getAmountSpent(cursor_id)
							- debt_per_person;
					// if debt become 0 delete the node
					if (delta == 0) {
						exist = true;
						mDebtsDb.deleteNode(cursor_id);
					}

					// if debt changes the direction of relation
					if (delta < 0) {
						exist = false;
						mDebtsDb.deleteNode(cursor_id);
						debt_per_person = -delta;
					}

					// if debt does not change the direction of relation
					if (delta > 0) {
						exist = true;
						mDebtsDb.setAmountSpent(cursor_id, delta);
					}
				}
				}
				// if relation does is not in DB
				if (!exist)
					mDebtsDb.createDebt(travel_id, debt_per_person, creditor, debtor);
			}

		}

		added = true;
		return added;
	}

	/**
	 * Method takes expense calculates spent amount and adds it to the list of
	 * each travelers money_spend field. As well generates debt relations in
	 * DB_table debts
	 * 
	 * @param travel_id
	 *            the id of current travel
	 * @param creditor
	 *            the id of creditor in DB
	 * @param debtors
	 *            id's of debtors in DB
	 * @param amount
	 *            the size of money spend
	 * @return Method returns true if additions to the databases are performed
	 *         successfully
	 */
	public boolean addAmountsSpentForExpense(int travel_id, int creditor,
			Vector debtors, int amnt) {

		boolean debtor_himself = false;
		int nrOfDebtorsSize = debtors.size();
		int debt_per_person = amnt / nrOfDebtorsSize;

		for (int i = 0; i < nrOfDebtorsSize; i++) {
			
			int debtor = ((Integer) debtors.elementAt(i)).intValue();
			// if creditor is not crediting himself
			Log.i("amount","travelId:"+travel_id+"creditor:"+creditor+" debtor:"+debtor);
			
			if (creditor != debtor) {
				Log.i("amount","true");
				// This step is computed for all debtors
				mTravellersDb.addToMoneyFlow(debtor, travel_id, -debt_per_person);
			} else {
				Log.i("amount","false");
				// Creditor is in the debtors list
				debtor_himself = true;
				mTravellersDb.addToMoneyFlow(creditor, travel_id, amnt - debt_per_person);
			}
		}

		// covers the case when creditor is not in debtors list
		if (!debtor_himself){
			Log.i("amount","creditor not in the list");
			mTravellersDb.addToMoneyFlow(creditor, travel_id, amnt);
		
		}
		return true;
	}
}
